package main

import (
	"fmt"
	"os"
	"strings"
	"time"
)

func exportTables(fields DbConnFields, flag OpFlag, ch chan<- string) error {
	ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Info: 正在导出表 ", flag.Table, "\r\n")
	fileName := fields.WorkDir + flag.Table + "-" + time.Now().Format("2006-01-02") + ".sql"
	ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Info: 生成数据文件 ", fileName, "\r\n")
	sqlStr := "SELECT	`COLUMNS`.COLUMN_NAME,`COLUMNS`.COLUMN_TYPE,`COLUMNS`.IS_NULLABLE," +
		"`COLUMNS`.CHARACTER_SET_NAME,`COLUMNS`.COLUMN_DEFAULT,`COLUMNS`.EXTRA," +
		"`COLUMNS`.COLUMN_KEY,`COLUMNS`.COLUMN_COMMENT,`STATISTICS`.TABLE_NAME," +
		"`STATISTICS`.INDEX_NAME,`STATISTICS`.SEQ_IN_INDEX,`STATISTICS`.NON_UNIQUE," +
		"`COLUMNS`.COLLATION_NAME " +
		"FROM information_schema.`COLUMNS` " +
		"LEFT JOIN information_schema.`STATISTICS` ON " +
		"information_schema.`COLUMNS`.TABLE_NAME = `STATISTICS`.TABLE_NAME " +
		"AND information_schema.`COLUMNS`.COLUMN_NAME = information_schema.`STATISTICS`.COLUMN_NAME " +
		"AND information_schema.`STATISTICS`.table_schema = ? " +
		"where information_schema.`COLUMNS`.TABLE_NAME = ? and `COLUMNS`.table_schema = ?"
	values := make([]interface{}, 0)
	values = append(values, fields.DbName, flag.Table, fields.DbName)
	rs, err := ExecuteWithDbConn(sqlStr, values, fields)
	if err != nil {
		ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Error: 导出表时连接数据库失败 ", flag.Table, "\r\n")
		return err
	}
	colRs := rs["rows"].([]map[string]interface{})
	var allFields []string
	for _, colAl := range colRs {
		allFields = append(allFields, "`"+colAl["COLUMN_NAME"].(string)+"`")
	}
	if flag.Istime {
		ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Info: 正在导出表数据 ", flag.Table, " 开始时间 ", flag.Start, " 结束时间 ", flag.Stop, "\r\n")
	} else {
		ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Info: 正在导出表数据 ", flag.Table, "\r\n")
	}

	err = exportTableData(fileName, fields, flag.Table, allFields, flag)
	if err != nil {
		ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Error: 导出表失败 ", flag.Table, "\r\n")
		return err
	}
	ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Info: 导出表成功 ", flag.Table, "\r\n")
	return nil
}

func exportTableData(fileName string, fields DbConnFields, tableName string, allFields []string, flag OpFlag) error {
	sqlStr := "select " + strings.Join(allFields, ",") + " from " + tableName
	if flag.Istime {
		sqlStr = sqlStr + " where " + flag.TimeField + " between " + flag.Start + " and " + flag.Stop
	}
	err := ExecuteWithDbConnWithWrite(sqlStr, make([]interface{}, 0), fields, tableName, fileName)
	if err != nil {
		return err
	}
	writeToFile(fileName, "\n", true)
	return nil
}

func writeToFile(name string, content string, append bool) {
	var fileObj *os.File
	var err error
	if append {
		fileObj, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
	} else {
		fileObj, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
	}
	if err != nil {
		fmt.Println("Failed to open the file", err.Error())
		os.Exit(2)
	}
	defer fileObj.Close()
	if _, err := fileObj.WriteString(content); err != nil {
		fmt.Println(err)
	}
}

func escape(source string) string {
	var j int
	if len(source) == 0 {
		return ""
	}
	tempStr := source[:]
	desc := make([]byte, len(tempStr)*2)
	for i := 0; i < len(tempStr); i++ {
		flag := false
		var escape byte
		switch tempStr[i] {
		case '\r':
			flag = true
			escape = '\r'
		case '\n':
			flag = true
			escape = '\n'
		case '\\':
			flag = true
			escape = '\\'
		case '\'':
			flag = true
			escape = '\''
		case '"':
			flag = true
			escape = '"'
		case '\032':
			flag = true
			escape = 'Z'
		default:
		}
		if flag {
			desc[j] = '\\'
			desc[j+1] = escape
			j = j + 2
		} else {
			desc[j] = tempStr[i]
			j = j + 1
		}
	}
	return string(desc[0:j])
}

func ExportOne(fields DbConnFields, workDir string, ch chan<- string, flag []OpFlag) {
	if _, err := os.Stat(workDir); os.IsNotExist(err) {
		ch <- fmt.Sprint(fields.DbHost + " " + fields.DbName + " Info: " + workDir + " 文件不存在,新建文件\r\n")
		os.Mkdir(workDir, 0777)
	}
	ch <- fmt.Sprint(fields.DbHost + " " + fields.DbName + " Info: 测试数据库连接\r\n")
	if err := TestDbConn(fields); err != nil {
		ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Error: ", fields.DbName, "\t test db connect throw, \t", err, "\r\n")
		return
	}
	ch <- fmt.Sprint(fields.DbHost + " " + fields.DbName + " Info: 数据库连接测试成功,正在导出数据\r\n")
	for _, subflag := range flag {
		err := exportTables(fields, subflag, ch)
		if err != nil {
			ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Error: ", subflag.Table, "\t export tables throw, \t", err, "\r\n")
			return
		}
	}

	ch <- fmt.Sprint(fields.DbHost+" "+fields.DbName+" Export ", fields.DbName, "\t success at \t", time.Now().Format("2006-01-02 15:04:05"), "\r\n")
	close(ch)
}
